package controllers

import (
	"beego/comm/db"
	"beego/comm/entity"
	"beego/comm/requests"
	"beego/comm/source"
	"encoding/json"
	"fmt"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/astaxie/beego"
	"github.com/astaxie/beego/orm"
)

type RemindDateController struct {
	beego.Controller
}

var (
	lockAddRemindDate sync.Mutex
)

func (c *RemindDateController) CheckLunar() {
	defer func() {
		err := recover()
		if nil != err {
			c.Data["json"] = map[string]interface{}{
				"lunar": false,
				"error": err,
			}
			c.ServeJSON()
		}
	}()
	var date_remind entity.Lunar
	json.Unmarshal(c.Ctx.Input.RequestBody, &date_remind)
	res_data := map[string]int{
		"year":  date_remind.Year,
		"month": date_remind.Month,
		"day":   date_remind.Day,
	}
	resp_data := requests.Post(source.Src.GetFlaskUrl()+"/is_lunar", res_data)
	var result map[string]interface{}
	json.Unmarshal([]byte(resp_data), &result)
	c.Data["json"] = result
	c.ServeJSON()
}

func (c *RemindDateController) AddRemindDate() {
	defer func() {
		err := recover()
		if nil != err {
			c.Data["json"] = map[string]interface{}{
				"add":   false,
				"error": err,
			}
			c.ServeJSON()
		}
	}()
	var date_remind entity.DateRemind
	json.Unmarshal(c.Ctx.Input.RequestBody, &date_remind)
	user_name := date_remind.UserName
	user_loginID := date_remind.LoginID
	loginID, err := db.RedisGet("login-" + user_name)
	if nil != err {
		panic(fmt.Sprintf("%s", err.Error()))
	}
	if "" == loginID || loginID != user_loginID {
		panic("请先登录")
	}
	description := date_remind.Description
	front := date_remind.Front
	back := date_remind.Back
	frequency := date_remind.Frequency
	date_type := date_remind.Type
	var date string
	if "阳历" == date_type {
		date = date_remind.Calendar
	} else if "阴历" == date_type {
		lunar := date_remind.Lunar
		date = fmt.Sprintf("%d-%d-%d", lunar["year"], lunar["month"], lunar["day"])
	} else {
		panic("未知的时间类型: " + date_type)
	}
	o := orm.NewOrm()
	var maps []orm.Params
	lockAddRemindDate.Lock()
	sql := `select cur_id from sequence where table_name = 'date_remind'`
	beego.Info(sql)
	o.Raw(sql).Values(&maps)
	cur_id, _ := strconv.ParseInt(maps[0]["cur_id"].(string), 10, 64)
	beego.Info("cur_id: ", cur_id)
	sql = fmt.Sprintf("insert into date_remind(id, user, date, type, description, front, back, frequency) "+
		"values('%d', '%s', '%s', '%s', '%s', %d, %d, '%s')",
		cur_id, user_name, date, date_type, description, front, back, frequency)
	beego.Info(sql)
	exe_result, err := o.Raw(sql).Exec()
	beego.Info(fmt.Sprintf("insert执行结果: %s", exe_result))
	beego.Info(fmt.Sprintf("执行状态: %s", err))
	cur_id += 1
	sql = fmt.Sprintf("update sequence set cur_id = '%d' where table_name = 'date_remind'", cur_id)
	beego.Info(sql)
	exe_result, err = o.Raw(sql).Exec()
	beego.Info(fmt.Sprintf("update执行结果: %s", exe_result))
	beego.Info(fmt.Sprintf("执行状态: %s", err))
	lockAddRemindDate.Unlock()
	c.Data["json"] = map[string]interface{}{
		"add":   true,
		"error": "",
	}
	c.ServeJSON()
}

func (c *RemindDateController) QueryRemindDate() {
	defer func() {
		err := recover()
		if nil != err {
			c.Data["json"] = map[string]interface{}{
				"data":  nil,
				"error": err,
			}
			c.ServeJSON()
		}
	}()
	var date_remind entity.DateRemind
	json.Unmarshal(c.Ctx.Input.RequestBody, &date_remind)
	user_name := date_remind.UserName
	user_loginID := date_remind.LoginID
	loginID, err := db.RedisGet("login-" + user_name)
	if nil != err {
		panic(fmt.Sprintf("%s", err.Error()))
	}
	if "" == loginID || loginID != user_loginID {
		panic("请先登录")
	}
	o := orm.NewOrm()
	var maps []orm.Params
	sql := fmt.Sprintf("select * from date_remind where user = '%s' order by date", user_name)
	beego.Info(sql)
	o.Raw(sql).Values(&maps)
	var date_remind_data []orm.Params = maps
	sql = fmt.Sprintf("select count(1) as count from date_remind where user = '%s'", user_name)
	beego.Info(sql)
	o.Raw(sql).Values(&maps)
	count64, _ := strconv.ParseInt(maps[0]["count"].(string), 10, 64)
	count := int(count64)
	c.Data["json"] = map[string]interface{}{
		"data":  date_remind_data,
		"count": count,
		"error": "",
	}
	c.ServeJSON()
}

func (c *RemindDateController) DelRemindDate() {
	defer func() {
		err := recover()
		if nil != err {
			c.Data["json"] = map[string]interface{}{
				"status": false,
				"error":  err,
			}
			c.ServeJSON()
		}
	}()
	var date_remind entity.DateRemindDel
	json.Unmarshal(c.Ctx.Input.RequestBody, &date_remind)
	user_name := date_remind.UserName
	user_loginID := date_remind.LoginID
	loginID, err := db.RedisGet("login-" + user_name)
	if nil != err {
		panic(fmt.Sprintf("%s", err.Error()))
	}
	if "" == loginID || loginID != user_loginID {
		panic("请先登录")
	}
	del_items := "("
	for _, item := range date_remind.Record {
		del_items += fmt.Sprintf("'%s', ", item)
	}
	del_items = del_items[:len(del_items)-2]
	del_items += ")"
	o := orm.NewOrm()
	sql := fmt.Sprintf("delete from date_remind where id in %s", del_items)
	beego.Info(sql)
	exe_result, err := o.Raw(sql).Exec()
	beego.Info(fmt.Sprintf("delete执行结果: %s", exe_result))
	beego.Info(fmt.Sprintf("执行状态: %s", err))
	c.Data["json"] = map[string]interface{}{
		"status": true,
		"error":  "",
	}
	c.ServeJSON()
}

func (c *RemindDateController) ModifyRemindDate() {
	defer func() {
		err := recover()
		if nil != err {
			c.Data["json"] = map[string]interface{}{
				"status": false,
				"error":  err,
			}
			c.ServeJSON()
		}
	}()
	var date_remind entity.DateRemind
	json.Unmarshal(c.Ctx.Input.RequestBody, &date_remind)
	user_name := date_remind.UserName
	user_loginID := date_remind.LoginID
	loginID, err := db.RedisGet("login-" + user_name)
	if nil != err {
		panic(fmt.Sprintf("%s", err.Error()))
	}
	if "" == loginID || loginID != user_loginID {
		panic("请先登录")
	}
	description := date_remind.Description
	front := date_remind.Front
	back := date_remind.Back
	frequency := date_remind.Frequency
	date_type := date_remind.Type
	var date string
	if "阳历" == date_type {
		date = date_remind.Calendar
	} else if "阴历" == date_type {
		lunar := date_remind.Lunar
		date = fmt.Sprintf("%d-%d-%d", lunar["year"], lunar["month"], lunar["day"])
	} else {
		panic("未知的时间类型: " + date_type)
	}
	set_items := fmt.Sprintf("description = '%s', ", description)
	if "" != strings.Trim(date_type, " ") {
		set_items += fmt.Sprintf("type = '%s', ", date_type)
	}
	if "" != strings.Trim(date, " ") {
		set_items += fmt.Sprintf("date = '%s', ", date)
	}
	if -1 != front {
		set_items += fmt.Sprintf("front = %d, ", front)
	}
	if -1 != back {
		set_items += fmt.Sprintf("back = %d, ", back)
	}
	if "" != strings.Trim(frequency, " ") {
		set_items += fmt.Sprintf("frequency = '%s', ", frequency)
	}
	set_items = set_items[:len(set_items)-2]
	o := orm.NewOrm()
	sql := fmt.Sprintf("update date_remind set %s where id = '%s'", set_items, date_remind.ID)
	beego.Info(sql)
	exe_result, err := o.Raw(sql).Exec()
	beego.Info(fmt.Sprintf("update执行结果: %s", exe_result))
	beego.Info(fmt.Sprintf("执行状态: %s", err))
	c.Data["json"] = map[string]interface{}{
		"status": true,
		"error":  "",
	}
	c.ServeJSON()
}

func strToDate(str string) time.Time {
	stamp, err := time.Parse("2006-01-02", str)
	if nil != err {
		panic(err.Error())
	}
	return stamp
}

func deltaDay(a time.Time, b time.Time) int {
	a2 := a.Unix()
	b2 := b.Unix()
	date := (a2 - b2) / 86400
	return int(date)
}

func replaceStrDate(date string, pos int, num int) string {
	result := ""
	str := strings.Split(date, "-")
	for index, word := range str {
		if pos == index {
			result += fmt.Sprintf("%d-", num)
		} else {
			result += word + "-"
		}
	}
	rune_str := []rune(result)
	rune_str = rune_str[:len(rune_str)-1]
	return string(rune_str)
}

func (c *RemindDateController) DateRemind() {
	defer func() {
		err := recover()
		if nil != err {
			c.Data["json"] = map[string]interface{}{
				"data":  nil,
				"error": err,
			}
			c.ServeJSON()
		}
	}()
	var date_remind entity.DateRemind
	json.Unmarshal(c.Ctx.Input.RequestBody, &date_remind)
	user_name := date_remind.UserName
	user_loginID := date_remind.LoginID
	loginID, err := db.RedisGet("login-" + user_name)
	if nil != err {
		panic(fmt.Sprintf("%s", err.Error()))
	}
	if "" == loginID || loginID != user_loginID {
		panic("请先登录")
	}
	o := orm.NewOrm()
	var maps []orm.Params
	sql := fmt.Sprintf("select * from date_remind where user = '%s' order by date", user_name)
	beego.Info(sql)
	o.Raw(sql).Values(&maps)
	var result []interface{}
	var lunar_date []map[string]interface{}
	today := time.Now()
	today_year := today.Year()
	today_month0, _ := strconv.ParseInt(fmt.Sprintf("%d", today.Month()), 10, 64)
	today_month := int(today_month0)
	for _, item := range maps {
		beego.Info(item)
		date_type := item["type"].(string)
		if "阴历" == date_type {
			lunar_date = append(lunar_date, item)
		} else if "阳历" == date_type {
			i_date := item["date"].(string)
			frequency := item["frequency"].(string)
			if "每年" == frequency {
				i_date = replaceStrDate(i_date, 0, today_year)
			} else if "每月" == frequency {
				i_date = replaceStrDate(i_date, 0, today_year)
				i_date = replaceStrDate(i_date, 1, today_month)
			} else {
				panic("不存在的提醒频率: " + frequency)
			}
			front0, _ := strconv.ParseInt(item["front"].(string), 10, 64)
			back0, _ := strconv.ParseInt(item["back"].(string), 10, 64)
			front := int(front0)
			back := int(back0)
			today_int := strToDate(today.Format("2006-01-02"))
			i_date_int := strToDate(i_date)
			d1 := deltaDay(today_int, i_date_int)
			d2 := deltaDay(i_date_int, today_int)
			if 0 == d1 {
				item["prompt"] = "就在今天"
				result = append(result, item)
			} else if d1 > 0 && d1 <= back {
				item["prompt"] = fmt.Sprintf("已过%d天", d1)
				result = append(result, item)
			} else if d2 > 0 && d2 <= front {
				item["prompt"] = fmt.Sprintf("还有%d天", d2)
				result = append(result, item)
			}
		} else {
			panic(fmt.Sprintf("不存在的日期类型: %s", item["type"]))
		}
	}
	if nil != lunar_date {
		res_data := map[string]interface{}{
			"date_list": lunar_date,
		}
		resp_data := requests.Post(source.Src.GetFlaskUrl()+"/lunar_filter", res_data)
		beego.Info(resp_data)
		var resp_result map[string]interface{}
		json.Unmarshal([]byte(resp_data), &resp_result)
		py_err := resp_result["error"].(string)
		if "" != py_err {
			panic(py_err)
		}
		py_data := resp_result["date_list"].([]interface{})
		result = append(result, py_data...)
	}
	c.Data["json"] = map[string]interface{}{
		"data":  result,
		"error": "",
	}
	c.ServeJSON()
}
